package com.tsinghua.server.common.utils;

import cn.hutool.core.util.StrUtil;
import com.tsinghua.server.common.Result;
import com.tsinghua.server.common.exception.BusinessException;
import com.tsinghua.server.train.entity.PyVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Component
public class BaseUtil {

    private static String pyFloderPath;
    private static String pyDataProcessingScript;
    private static String pyModelTrainingScript;
    private static String pyModelOperationScript;

    @Value("${py.floder_path}")
    public void setPyFloderPath(String floder_path) {
        pyFloderPath = floder_path;
    }

    @Value("${py.data-processing-script}")
    public void setPyDataProcessingScript(String data_processing_script) {
        pyDataProcessingScript = data_processing_script;
    }

    @Value("${py.model-training-script}")
    public void setPyModelTrainingScript(String model_training_script) {
        pyModelTrainingScript = model_training_script;
    }

    @Value("${py.model-operation-script}")
    public void setPyModelOperationScript(String model_operation_script) {
        pyModelOperationScript = model_operation_script;
    }

    /**
     * 判断obj是否为空，为空返回true
     *
     * @param obj
     * @return true 对象为空
     */
    public static boolean isNull(Object obj) {
        if (Objects.isNull(obj) || StrUtil.isBlank(obj.toString())) {
            return true;
        }
        return false;
    }

    /**
     * 判断传入的对象数组是不是都不为空
     * 都不为空返回true
     *
     * @param objects : 对象列表
     * @return boolean
     */
    public static boolean isAllNotNull(Object... objects) {
        return !isAnyNull(objects);
    }

    /**
     * 判断传入的objs列表是否存在为null的值
     * 1：若objs本身为null或者空数组也返回true
     * 2：只要存在一个为null即返回true
     *
     * @param objs : 对象数组
     * @return boolean
     */
    public static boolean isAnyNull(Object... objs) {
        if (ArrayUtil.isEmpty(objs)) {
            return true;
        }
        for (Object obj : objs) {
            if (isNull(obj)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断传入的objs列表是否都是null
     * 1：若objs本身为null或者空数组也返回true
     * 2：若objs中的对象都是null返回true
     *
     * @param objs : 对象数组
     * @return boolean
     */
    public static boolean isAllNull(Object... objs) {
        if (ArrayUtil.isEmpty(objs)) {
            return true;
        }
        for (Object obj : objs) {
            if (isNotNull(obj)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断obj是否不为空
     *
     * @param obj
     * @return
     */
    public static boolean isNotNull(Object obj) {
        return !isNull(obj);
    }

    /**
     * 判断当前对象是否是boolean类型的对象
     * 为空或者非boolean型返回false
     *
     * @param obj
     * @return boolean
     */
    public static boolean isBooleanObj(Object obj) {
        if (isNull(obj)) {
            return false;
        }
        return (obj instanceof Boolean && boolean.class.equals(obj.getClass()));
    }

    /**
     * 比较两个对象是否相等、若为原始类型与包装类型比较则将原始类型放第二个参数
     *
     * @param obj1
     * @param obj2
     */
    public static boolean equals(Object obj1, Object obj2) {
        if (isNull(obj1) || isNull(obj2)) {
            return false;
        }
        if (obj1.equals(obj2)) {
            return true;
        }
        return false;
    }

    /**
     * 比较两个对象是否不相等、若为原始类型与包装类型比较则将原始类型放第二个参数
     *
     * @param obj1
     * @param obj2
     */
    public static boolean notEquals(Object obj1, Object obj2) {
        return !equals(obj1, obj2);
    }

    /**
     * 实体类属性存在空字符串""则转换为null
     * @param object
     */
    public static void convertEmptyToNull(Object object) {
        try {
            Field[] fs = object.getClass().getDeclaredFields();
            for(int i =0; i < fs.length;i++) {
                Field f = fs[i];
                f.setAccessible(true);
                Object val = f.get(object);
                String type = f.getType().toString();
                if(type.endsWith("String")) {
                    if(val !=null && val.equals("")) {
                        f.set(object, null);
                    }
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BusinessException(String.format("converEmptyNullToString fail -> {}",e.getMessage()));
        }
    }


    /**
     * 调用python脚本根据传参类型，形成入参
     * @param pyType 1.数据处理 2.模型训练 3.模型运行
     * @param dataType  数据类型 '城投债'，'产业债'，'银行债', '保险债', '证券债'
     */
    public static HashMap getPyParam(Integer pyType,String dataType) {
        log.info("执行python处理");
        String pyPath = "";
        HashMap<String,String> param = new HashMap<String,String>();
        // 数据处理
        if(pyType == 1) {
            log.info("---进行数据处理---");
            log.info(pyFloderPath);
            log.info(pyDataProcessingScript);
            param.put("pyPath",pyFloderPath+pyDataProcessingScript);
            if(dataType.equals("城投债")) {
                param.put("InputTable", "fxjc_ctz_base");
                param.put("OutputTable", "fxjc_ctz_molding");
            } else if(dataType.equals("产业债")) {
                param.put("InputTable", "fxjc_cyz_base");
                param.put("OutputTable", "fxjc_cyz_molding");
            } else if(dataType.equals("银行债")) {
                param.put("InputTable", "fxjc_yh_base");
                param.put("OutputTable", "fxjc_yh_molding");
            } else if(dataType.equals("保险债")) {
                param.put("InputTable", "fxjc_bx_base");
                param.put("OutputTable", "fxjc_bx_molding");
            } else if(dataType.equals("证券债")) {
                param.put("InputTable", "fxjc_zq_base");
                param.put("OutputTable", "fxjc_zq_molding");
            }
        } else if(pyType == 2) {
            log.info("-------2------");
            log.info(pyFloderPath);
            log.info(pyDataProcessingScript);
            param.put("pyPath",pyFloderPath+pyModelTrainingScript);
            if(dataType.equals("城投债")) {
                param.put("InputTable", "fxjc_ctz_molding");
                param.put("OutputTable", "fxjc_ctz_traning_result");
            } else if(dataType.equals("产业债")) {
                param.put("InputTable", "fxjc_cyz_molding");
                param.put("OutputTable", "fxjc_cyz_traning_result");
            } else if(dataType.equals("银行债")) {
                param.put("InputTable", "fxjc_yh_molding");
                param.put("OutputTable", "fxjc_yh_traning_result");
            } else if(dataType.equals("保险债")) {
                param.put("InputTable", "fxjc_bx_molding");
                param.put("OutputTable", "fxjc_bx_traning_result");
            } else if(dataType.equals("证券债")) {
                param.put("InputTable", "fxjc_zq_molding");
                param.put("OutputTable", "fxjc_zq_traning_result");
            }
        } else if(pyType == 3) {
            log.info("-----3-----");
            param.put("pyPath",pyFloderPath+pyModelOperationScript);
            if(dataType.equals("城投债")) {
                param.put("InputTable", "fxjc_ctz_molding_operation_input");
                param.put("OutputTable", "fxjc_ctz_molding_operation_output");
            } else if(dataType.equals("产业债")) {
                param.put("InputTable", "fxjc_cyz_molding_operation_input");
                param.put("OutputTable", "fxjc_cyz_molding_operation_output");
            } else if(dataType.equals("银行债")) {
                param.put("InputTable", "fxjc_yh_molding_operation_input");
                param.put("OutputTable", "fxjc_yh_molding_operation_output");
            } else if(dataType.equals("保险债")) {
                param.put("InputTable", "fxjc_bx_molding_operation_input");
                param.put("OutputTable", "fxjc_bx_molding_operation_output");
            } else if(dataType.equals("证券债")) {
                param.put("InputTable", "fxjc_zq_molding_operation_input");
                param.put("OutputTable", "fxjc_zq_molding_operation_output");
            }
        }
        System.out.println("返回参数: "+param);
        return param;
    }


    public static Result execPyScript(PyVo pyVo) throws IOException, InterruptedException {
        System.out.println("拿到pyVo");
        System.out.println(pyVo);
        HashMap<String,String> pyParam = BaseUtil.getPyParam(pyVo.getPyType(),pyVo.getDataType());
        String[] args;
        if(pyVo.getPyType() == 1) {
            args = new String[]{"python3",pyParam.get("pyPath"),pyParam.get("InputTable"), pyParam.get("OutputTable"), pyVo.getDataType()};
        } else if(pyVo.getPyType() == 2) {
            System.out.println("进入第二个python方法");
            System.out.println(pyParam.get("pyPath"));
            System.out.println(pyParam.get("InputTable"));
            System.out.println(pyParam.get("OutputTable"));
            args = new String[]{"python3",pyParam.get("InputTable"), pyParam.get("OutputTable"),pyVo.getModelName(), pyVo.getDataType()};
        } else {
            args = new String[]{"python3",pyParam.get("pyPath"),pyParam.get("InputTable"), pyParam.get("OutputTable"),pyVo.getModelName(), pyVo.getDataType()};
        }
        Process proc = Runtime.getRuntime().exec(args);
        BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
        String line = null;
        while ((line = in.readLine()) != null) {
            System.out.println(line);
        }
        in.close();
        proc.waitFor();
        return Result.succ(true);
    }

}
